[Java] 今年流行るかもしれないDropwizardフレームワークを使ってみる
Javaが動く環境だけあればOKなWebサービスフレームワーク
また新しいJavaのフレームワークかよ!と思ったのですが、 実際に少し使ってみると、いままでにない(自分が知らなかった)タイプのフレームワークでした。 今回は、(一部で)今年大ブレイクが予想されているらしい、「Dropwizard」というフレームワークの紹介をします。
Dropwizardは元々YammerのバックエンドWebサービスを提供するために作られたフレームワークだそうです。 このフレームワークが持つ基本的な機能は以下のとおりです。
- 組み込みWebサーバ(Jetty)
- JaxRSベースのRESTフレームワーク(Jersey)
- ORM
- Metricsを収集するためのライブラリや監視ツール
機能だけを見るとどこにでもあるようなフレームワークかと思いますが、 特徴的なのはこのフレームワークを使用したアプリのデプロイ方法です。 Dropwizardは、ビルド時に依存するライブラリをすべて1つのjarにパッケージングし、 組み込みのJettyサーバを利用します。 なお、ビルドするためのツールはmaven/gradle/sbt等なんでもOKです。
デプロイとして必要な作業はパッケージングされたjarファイルとymlファイルを置いて、 通常のJavaアプリケーションとして起動するだけです。
java -jar yourDropWizardApp.jar server your-dropwizard-config.yml
環境変数はymlファイルに定義しておくので、Java実行環境だけあればどこでも動作します。 では、ここを参考に、Mavenを使用してDropWizardアプリを試してみましょう。
環境構築方法
今回使用した動作環境は以下のとおりです。
- OS : MacOS X 10.9
- Java : 1.7.0_45
- Maven : 3.1.1
サンプルプロジェクト作成
まずはMavenでひな形となるプロジェクトを作成します。
% mkdir dropwizard && cd dropwizard % mvn archetype:create -DgroupId=com.example -DartifactId=sample % cd sample
pomの作成
pom.xmlに、次のようにdropwizardライブラリ追加し、 maven-shade-pluginプラグインとmaven-jar-pluginを追加しましょう。
・ ・ <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.6</version> <configuration> <createDependencyReducedPom>true</createDependencyReducedPom> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.example.HelloWorldService</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.3.2</version> <configuration> <archive> <manifest> <addDefaultImplementationEntries>true</addDefaultImplementationEntries> </manifest> </archive> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>com.yammer.dropwizard</groupId> <artifactId>dropwizard-core</artifactId> <version>0.6.2</version> </dependency> </dependencies> ・ ・
Configクラスの作成
pom.xmlができたらConfigurationクラスを作成します。 src/main/java/com/exampleディレクトリにHelloWorldConfiguration.javaを次のように作成します。
package com.example; import com.yammer.dropwizard.config.Configuration; import com.fasterxml.jackson.annotation.JsonProperty; import org.hibernate.validator.constraints.NotEmpty; public class HelloWorldConfiguration extends Configuration { @NotEmpty @JsonProperty private String template; @NotEmpty @JsonProperty private String defaultName = "Stranger"; public String getTemplate() { return template; } public String getDefaultName() { return defaultName; } }
環境固有のパラメータを指定Configurationクラスでは環境固有のパラメータを設定します。 パラメータは、この後作成するymlファイルで指定します。
pom.xmlと同じ階層に、下記内容でhello-world.ymlを作成します。 ここで記述しているtemplateとdefaultNameはHelloWorldConfigurationのフィールドと対応します。
template: Hello, %s! defaultName: Stranger
サービスクラスの作成
次にアプリのエンドポイントとなるサービスクラスを作成します。 ここのmainメソッドでrunメソッドを呼び出します。runメソッドではこのあと作成するリソースクラスを登録したり、 healthチェックの登録をしたりしています。
package com.example; import com.yammer.dropwizard.Service; import com.yammer.dropwizard.config.Bootstrap; import com.yammer.dropwizard.config.Environment; import com.example.resources.HelloWorldResource; import com.example.health.TemplateHealthCheck; public class HelloWorldService extends Service<HelloWorldConfiguration> { public static void main(String[] args) throws Exception { new HelloWorldService().run(args); } @Override public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) { bootstrap.setName("hello-world"); } @Override public void run(HelloWorldConfiguration configuration, Environment environment) { final String template = configuration.getTemplate(); final String defaultName = configuration.getDefaultName(); environment.addResource(new HelloWorldResource(template, defaultName)); environment.addHealthCheck(new TemplateHealthCheck(template)); } }
リソースクラスの作成
次に、JSON形式のレスポンスを返すため、POJOを作成します。 src/main/java/com/example/coreディレクトリを作成し、Saying.javaを作成しましょう、
package com.example.core; public class Saying { private final long id; private final String content; public Saying(long id, String content) { this.id = id; this.content = content; } public long getId() { return id; } public String getContent() { return content; } }
そしてsrc/main/java/com/example/resourcesにリソースクラスを作成します。(HelloWorldResource.java) このクラスはアノテーションでURIに紐付いています。
package com.example.resources; import com.example.core.Saying; import com.google.common.base.Optional; import com.yammer.metrics.annotation.Timed; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import java.util.concurrent.atomic.AtomicLong; @Path("/hello-world") @Produces(MediaType.APPLICATION_JSON) public class HelloWorldResource { private final String template; private final String defaultName; private final AtomicLong counter; public HelloWorldResource(String template, String defaultName) { this.template = template; this.defaultName = defaultName; this.counter = new AtomicLong(); } @GET @Timed public Saying sayHello(@QueryParam("name") Optional<String> name) { return new Saying(counter.incrementAndGet(), String.format(template, name.or(defaultName))); } }
/hello-worldに対してGETリクエストを送ると、sayHelloメソッドが実行されます。 返り値には先ほど作成したSayingを返しています。
Health Checkクラスの作成
最後に、src/main/java/com/example/healthディレクトリを作成し、TemplateHealthCheck.javaを作成しましょう。 このクラスはアプリの状態をチェックするために必要になります。
package com.example.health; import com.yammer.metrics.core.HealthCheck; public class TemplateHealthCheck extends HealthCheck { private final String template; public TemplateHealthCheck(String template) { super("template"); this.template = template; } @Override protected Result check() throws Exception { final String saying = String.format(template, "TEST"); if (!saying.contains("TEST")) { return Result.unhealthy("template doesn't include a name"); } return Result.healthy(); } }
ビルドと動作確認
ソースの記述がおわったらビルドします。
% mvn package ・ ・ [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 7.955s [INFO] Finished at: Thu Jan 09 14:31:06 JST 2014 [INFO] Final Memory: 7M/81M [INFO] ------------------------------------------------------------------------
ビルドが成功すると、targetディレクトリにsample-1.0-SNAPSHOT.jarができています。 javaコマンドで起動してみましょう。
% java -jar target/sample-1.0-SNAPSHOT.jar server hello-world.yml
ブラウザでhttp://localhost:8080/hello-worldにアクセスしてみてください。 レスポンスがJSONで表示されます。また、nameパラメータを指定することもできます。 そして、http://localhost:8081/healthにアクセスすると、healthチェック情報を確認することができます。
まとめ
とりあえずGetting Startedのサンプルを動かしてみました。 APサーバを用意しなくてもjarを1つ渡せば環境構築の手間も省けますし、 簡単にWebサービスを動作させることができるのは非常に便利なのではないでしょうか。